﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Diagnostics;

namespace agent
{
    /// <summary>
    /// 监控指标
    /// </summary>
    class Indicator
    {
        /// <summary>
        /// 监控指标配置文件路径
        /// </summary>
        private const string str_ConfPath = @"../../conf/indicator.conf";
        /// <summary>
        /// 监控指标表（键值对），存储被监控进程和监控级别。
        /// </summary>
        private Hashtable hash_Indcators;

        /// <summary>
        /// 监控指标表属性
        /// </summary>
        public Hashtable Hash_Indcators
        {
            get
            {
                return this.hash_Indcators;
            }
        }

        /// <summary>
        /// 初始化监控指标类，并从默认配置文件中读取监控指标。
        /// </summary>
        public Indicator()
        {
            string str_Line;
            string[] str_Ind;

            this.hash_Indcators = new Hashtable();

            StreamReader reader = new StreamReader(Indicator.str_ConfPath);
            while (true)
            {
                str_Line = reader.ReadLine();
                if (str_Line == null)
                {
                    break;
                }
                if (str_Line.IndexOf('#') != 0 && str_Line != "")
                {
                    str_Ind = str_Line.Trim().Split('=');
                    try
                    {
                        this.hash_Indcators.Add(str_Ind[0].ToLower(), Enum.Parse(typeof(OptLevel), str_Ind[1].ToUpper()));
                    }
                    catch
                    {
                        //增加重复的项，或增加的项不合法
                    }
                }
            }

            reader.Close();
        }

        /// <summary>
        /// 向指标集中增加指标
        /// </summary>
        /// <param name="processName">进程名称</param>
        /// <param name="lv">操作状态级别</param>
        /// <returns>是否加入成功</returns>
        public bool AddInd(String processName, OptLevel lv)
        {
            try
            {
                this.hash_Indcators.Add(processName.ToLower(), lv);
                return true;
            }
            catch
            {
                //增加重复的项
                return false;
            }
        }

        /// <summary>
        /// 通过进程名获取它的操作状态级别
        /// </summary>
        /// <param name="processName">进程名</param>
        /// <returns>操作状态级别</returns>
        public OptLevel GetOptLevle(String processName)
        {
            OptLevel lv = OptLevel.OPT_LV_OK;

            foreach (DictionaryEntry de in this.hash_Indcators)
            {
                if (((string)de.Key) == processName.ToLower())
                {
                    lv = (OptLevel)de.Value;
                    break;
                }
            }

            return lv;
        }

        /// <summary>
        /// 移除监控指标
        /// </summary>
        /// <param name="processName">监控的进程名</param>
        public void RemoveInd(string processName)
        {
            this.hash_Indcators.Remove(processName.ToLower());
        }

        /// <summary>
        /// 移除所有监控指标
        /// </summary>
        public void ClearInd()
        {
            this.hash_Indcators.Clear();
        }
    }

    /// <summary>
    /// 主机操作条目、日志
    /// </summary>
    class HostOptEntry
    {
        /// <summary>
        /// 时间
        /// </summary>
        private int time;
        /// <summary>
        /// 基础操作代码，将enum HostOpt转换为对应的数字
        /// </summary>
        private byte optBase;
        /// <summary>
        /// 扩展操作代码
        /// </summary>
        private byte optExtension;
        /// <summary>
        /// 主机位图
        /// </summary>
        private byte hostMap;
        /// <summary>
        /// 主机操作状态级别，将enum OptLevel转换为对应的数字
        /// </summary>
        private byte hostLevle;
        /// <summary>
        /// 主机操作的内容
        /// </summary>
        private byte[] data;
        /// <summary>
        /// 发送Entry的程序名
        /// </summary>
        private const string sendExePath = "SendHostOptEntry.exe";

        private bool isLongParam;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="isLongParam">是否是长参数，长参数为6个参数，短参数为4个参数</param>
        public HostOptEntry(bool isLongParam)
        {
            this.isLongParam = isLongParam;
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="time">时间</param>
        /// <param name="optBase">基础操作代码</param>
        /// <param name="optExtension">扩展操作代码</param>
        /// <param name="map">主机位图</param>
        /// <param name="lv">操作状态级别</param>
        /// <param name="data">操作内容</param>
        public HostOptEntry(DateTime time, HostOpt optBase, HostOpt optExtension, byte map, OptLevel lv, string data)
        {
            this.time = (Int32)((time.Ticks - new DateTime(1970, 1, 1, 8, 0, 0).Ticks) / 10000000);
            this.optBase = Convert.ToByte(Convert.ToInt32(optBase.ToString("d")));
            this.optExtension = Convert.ToByte(Convert.ToInt32(optExtension.ToString("d")));
            this.hostMap = map;
            this.hostLevle = Convert.ToByte(Convert.ToInt32(lv.ToString("d")));
            this.data = Encoding.ASCII.GetBytes(data);
        }
        /// <summary>
        /// 设置时间
        /// </summary>
        /// <param name="time">时间</param>
        public void SetTime(DateTime time)
        {
            DateTime dt = new DateTime(1970, 1, 1, 8, 0, 0);
            this.time = (Int32)((time.Ticks - dt.Ticks) / 10000000);
        }
        /// <summary>
        /// 设置操作代码
        /// </summary>
        /// <param name="optBase">基础操作代码</param>
        /// <param name="optExtension">扩展操作代码</param>
        public void SetOpt(HostOpt optBase, HostOpt optExtension)
        {
            this.optBase = Convert.ToByte(Convert.ToInt32(optBase.ToString("d")));
            this.optExtension = Convert.ToByte(Convert.ToInt32(optExtension.ToString("d")));
        }
        /// <summary>
        /// 设置主机位图
        /// </summary>
        /// <param name="map">主机位图</param>
        public void SetHostMap(byte map)
        {
            this.hostMap = map;
        }
        /// <summary>
        /// 设置主机操作状态级别
        /// </summary>
        /// <param name="lv"></param>
        public void SetOptLevel(OptLevel lv)
        {
            this.hostLevle = Convert.ToByte(Convert.ToInt32(lv.ToString("d")));
        }
        /// <summary>
        /// 设置主机操作内容
        /// </summary>
        /// <param name="data">操作内容</param>
        public void SetData(string data)
        {
            this.data = Encoding.ASCII.GetBytes(data);
        }
        /// <summary>
        /// 发送Entry
        /// </summary>
        /// <returns>返回是否发送成功</returns>
        public bool SendEntry()
        {
            Process p = new Process();

            if (this.isLongParam == true)
            {
                p.StartInfo.Arguments = this.time.ToString() + " " + this.optBase.ToString() + " " + this.optExtension.ToString() + " " + this.hostMap.ToString() + " " +
                                               this.hostLevle.ToString() + " " + Encoding.ASCII.GetString(this.data);
            }
            else
            {
                p.StartInfo.Arguments = this.time.ToString() + " " + this.optBase.ToString() + " " + this.hostMap.ToString() + " " + this.hostLevle.ToString();
            }
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.FileName = HostOptEntry.sendExePath;
            p.StartInfo.WorkingDirectory = ".";
            p.StartInfo.UseShellExecute = false;
            p.Start();

            return true;
        }
    }

    /// <summary>
    /// 进程采集类
    /// </summary>
    class Probe
    {
        /// <summary>
        /// 本次采集的进程信息
        /// </summary>
        private Process[] p_AllProc_Now;
        /// <summary>
        /// 上次采集的进程信息
        /// </summary>
        private Process[] p_AllProc_Last;
        /// <summary>
        /// 采集到新打开的进程
        /// </summary>
        private ArrayList arr_DiffProc_Open;
        /// <summary>
        /// 采集到新结束的进程
        /// </summary>
        private ArrayList arr_DiffProc_Close;
        /// <summary>
        /// 监控指标
        /// </summary>
        private Indicator ind;
        /// <summary>
        /// 主机操作日志
        /// </summary>
        private HostOptEntry entry6;
        private HostOptEntry entry4;

        /// <summary>
        /// 构造函数
        /// </summary>
        public Probe()
        {
            this.p_AllProc_Now = null;
            this.p_AllProc_Last = null;
            this.arr_DiffProc_Close = new ArrayList();
            this.arr_DiffProc_Open = new ArrayList();
            this.ind = new Indicator();
            this.entry6 = new HostOptEntry(true);
            this.entry4 = new HostOptEntry(false);
        }

        /// <summary>
        /// 采集一次
        /// </summary>
        /// <returns>是否采集成功</returns>
        public bool ProbeOnce()
        {
            if (this.p_AllProc_Now != null)
            {
                this.p_AllProc_Last = this.p_AllProc_Now.Clone() as Process[];
                this.p_AllProc_Now = Process.GetProcesses();
                this.GetDifference();
                this.SendEntry();
            }
            else                                //第一次采集
            {
                this.p_AllProc_Now = Process.GetProcesses();
                this.p_AllProc_Last = this.p_AllProc_Now.Clone() as Process[];
                this.SendAllEntry();
            }

            return true;
        }

        /// <summary>
        /// 比较两次采集中新打开和结束的进程
        /// </summary>
        private void GetDifference()
        {
            bool isSame;

            isSame = false;
            this.arr_DiffProc_Close.Clear();

            foreach (Process p1 in this.p_AllProc_Last)
            {
                if (String.Compare(p1.ProcessName, "SendHostOptEntry") == 0)
                {
                    continue;
                }

                foreach (Process p2 in this.p_AllProc_Now)
                {
                    if (String.Compare(p1.ProcessName, "SendHostOptEntry") == 0)
                    {
                        continue;
                    }
                    if (p1.Id == p2.Id)
                    {
                        isSame = true;
                        break;
                    }
                }

                if (isSame == false)
                {
                    this.arr_DiffProc_Close.Add(p1);
                }
                isSame = false;
            }


            isSame = false;
            this.arr_DiffProc_Open.Clear();
            foreach (Process p1 in this.p_AllProc_Now)
            {
                if (String.Compare(p1.ProcessName, "SendHostOptEntry") == 0)
                {
                    continue;
                }

                foreach (Process p2 in this.p_AllProc_Last)
                {
                    if (String.Compare(p1.ProcessName, "SendHostOptEntry") == 0)
                    {
                        continue;
                    }

                    if (p1.Id == p2.Id)
                    {
                        isSame = true;
                        break;
                    }
                }

                if (isSame == false)
                {
                    this.arr_DiffProc_Open.Add(p1);
                }
                isSame = false;
            }

        }

        /// <summary>
        /// 发送主机操作日志、条目
        /// </summary>
        private void SendEntry()
        {
            foreach (Process p in this.arr_DiffProc_Close)
            {
                this.entry6.SetTime(DateTime.Now);
                this.entry6.SetOpt(HostOpt.OPT_RUN, HostOpt.OPT_CLOSE);
                //
                //TODO  实现主机位图发送接收模块
                //
                this.entry6.SetHostMap(1);
                this.entry6.SetOptLevel(this.ind.GetOptLevle(p.ProcessName.ToString()));
                this.entry6.SetData(p.ProcessName.ToString());

                this.entry6.SendEntry();
            }

            foreach (Process p in this.arr_DiffProc_Open)
            {
                this.entry6.SetTime(DateTime.Now);
                this.entry6.SetOpt(HostOpt.OPT_RUN, HostOpt.OPT_OPEN);
                //
                //TODO  实现主机位图发送接收模块
                //
                this.entry6.SetHostMap(1);
                this.entry6.SetOptLevel(this.ind.GetOptLevle(p.ProcessName.ToString()));
                this.entry6.SetData(p.ProcessName.ToString());

                this.entry6.SendEntry();
            }
        }
        /// <summary>
        /// 发送所有主机操作条目
        /// </summary>
        private void SendAllEntry()
        {
            foreach (Process p in this.p_AllProc_Now)
            {
                this.entry6.SetTime(DateTime.Now);
                this.entry6.SetOpt(HostOpt.OPT_RUN, HostOpt.OPT_OPEN);
                //
                //TODO  实现主机位图发送接收模块
                //
                this.entry6.SetHostMap(1);
                this.entry6.SetOptLevel(this.ind.GetOptLevle(p.ProcessName.ToString()));
                this.entry6.SetData(p.ProcessName.ToString());

                this.entry6.SendEntry();
            }
        }
        /// <summary>
        /// 发送主机事件，包括开机、关机、注销等
        /// </summary>
        public void SendEvent(HostOpt opt)
        {
            if (opt != HostOpt.OPT_POWER && opt != HostOpt.OPT_SHUTDOWN && opt != HostOpt.OPT_LOGOUT)
            {
                return;
            }

            this.entry4.SetTime(DateTime.Now);
            this.entry4.SetOpt(opt, HostOpt.OPT_SURF);
            //
            //TODO  实现主机位图发送接收模块
            //
            this.entry4.SetHostMap(1);
            this.entry4.SetOptLevel(OptLevel.OPT_LV_OK);

            this.entry4.SendEntry();
        }
    }
}
